home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-08-31 | 21.8 KB | 495 lines | [TEXT/CCL ] |
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; Copyright 1990 by Ruben Kleiman for Apple Computer, Inc.
- ;;; Advanced Technology Group
- ;;;
- ;;;
-
- ;;;
- ;;; RESOURCE MANAGEMENT UTILITIES
- ;;;
- ;;; WARNING: This has not received heavy use, so consider it late ALPHA
- ;;; and tell me about bugs (include your phone number or INTERNET
- ;;; address):
- ;;;
- ;;; Ruben Kleiman
- ;;; Apple Computer, Inc. MS 76-3D
- ;;; 20525 Mariani Avenue
- ;;; Cupertino, CA 95014
- ;;;
-
- (eval-when (eval compile)
- (require :traps))
-
- ;; FUNCTION SUMMARY:
- ;;
- ;; transfer-resource -- copy, move, delete, or modify any resource; create resource files
- ;; open-resource-file -- open a resource file
- ;; get-resource-handle -- get a resource
- ;; get-resource-info -- get resource type, id, name and size, given its handle
- ;; map-resources -- apply function over all resources of given type
- ;; delete-resource -- delete a resource from its file
- ;; get-unique-resource-id -- get unique id for resource of given type
- ;; count-types -- returns number of resources of given type
- ;; restype-from-string -- returns Macintosh ResType integers for a Lisp string naming a resource type
- ;; string-from-restype -- converse of restype-from-string
- ;;
- ;;
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;restype-from-string
- ;;
- ;; Given a string naming a resource type, it returns two values:
- ;; the high word and the low word of the resource type expected
- ;; by resource manager toolbox calls.
- ;; It's the inverse of string-from-restype
- ;;
- (defun restype-from-string (type)
- (values (+ (* 256 (char-code (elt type 2)))
- (char-code (elt type 3)))
- (+ (* 256 (char-code (elt type 0)))
- (char-code (elt type 1)))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;string-from-restype
- ;;
- ;; Given a resource type as a long integer, returns a type string.
- ;; It's the inverse of restype-from-string.
- ;;
- (defun string-from-restype (high low
- &aux (longint (+ (* (expt 2 16) high) low))
- (type " ")
- (count -1))
- (mapcar #'(lambda (i)
- (setf (schar type (incf count))
- (code-char (ldb (byte 8 i) longint))))
- (list 8 0 24 16))
- type)
-
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;open-resource-file
- ;;
- ;; Given a filename, opens its resource fork.
- ;; Returns the file reference number.
- ;;
- (defun open-resource-file (filename)
- (let ((tempfile (with-pstrs ((tempfile (namestring (car (directory filename)))))
- (_openresfile :errchk :ptr tempfile :word))))
- (if (/= tempfile -1)
- tempfile)))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;convert-handle-to-resource
- ;;
- ;; Given a handle, converts it to a resource of the given type and ID. Type must
- ;; be a resource type (a four-character string) and ID a number. If ID is not
- ;; supplied, then a unique resource ID will be generated. The optional filename
- ;; should be a file into which you want the resource to be associated, else
- ;; the resource will be associated with the currently opened resource file.
- ;; If the supplied filename does not exist, then a file with that pathname will be created.
- ;; The optional argument DELETE-OLD allows you to specify whether a resource
- ;; of the same type and ID should be deleted or not if it is in the same
- ;; resource file with which the new resource is to be associated. The optional argument
- ;; RESOURCE-NAME allows you to give the new resource a name; else a null string
- ;; will be given.
- ;;
- (defun convert-handle-to-resource (handle type
- &key
- (ID (get-unique-resource-id type))
- (filename nil)
- (delete-old t)
- (resource-name "")
- &aux
- (filerefnum nil)
- (current-refnum (_curresfile :errchk :word))
- (a-resource-handle nil))
- (unwind-protect
- (progn
- ;; SET & POSSIBLE CREATE RESOURCE FILE TO WRITE TO:
- (setq filerefnum
- (when filename
- (setq filename (expand-logical-namestring filename))
- (if (probe-file filename)
- (open-resource-file filename)
- (with-pstrs ((fn filename))
- (_createresfile :errchk :ptr fn)
- (_reserror :errchk)
- (prog1 (_openresfile :errchk :ptr fn :word)
- (_reserror :errchk))))))
- (or filerefnum
- (setq filerefnum current-refnum))
- (multiple-value-bind (type-high type-low)
- (restype-from-string type)
- ;; NOW REMOVE ANY RESOURCES OF SAME TYPE & ID IN OUTPUT FILE:
- (loop
- (setq a-resource-handle
- (_getresource :word type-high :word type-low
- :word ID :ptr))
- (_reserror :errchk)
- (if (/= (_homeresfile :errchk :ptr a-resource-handle :word)
- filerefnum)
- (return nil)
- (if delete-old (delete-resource a-resource-handle))))
- (setq a-resource-handle nil) ; WATCH IT!
- ;; NOW WE CAN ADD THE RESOURCE!
- (with-pstrs ((name resource-name))
- (_addresource :errchk :ptr handle
- :word type-high :word type-low
- :word ID :ptr name))
- (_reserror :errchk)
- (_SetResAttrs :errchk :ptr handle :word 0)
- (_reserror :errchk)
- (_changedresource :errchk :ptr handle)
- (_reserror :errchk)
- (_updateresfile :errchk :word filerefnum)
- (_reserror :errchk)))
- (when (/= current-refnum filerefnum)
- (_useresfile :errchk :word current-refnum)
- (_reserror :errchk))
- (values type ID)))
-
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;count-Types
- ;;
- ;; Given a resource type, returns the number of resources there are of
- ;; this type in currently opened resource files.
- ;;
- (defun count-Types (type)
- (multiple-value-bind (high low)
- (restype-from-string type)
- (_CountResources :errchk :word high :word low :word)))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;map-resources
- ;;
- ;; Given a resource type and a function, calls the
- ;; FUNCTION once with each resource of that TYPE in
- ;; any opened resource file or in a specific resource file.
- ;; RESOURCE-FILENAME may be any particular file which you want to search.
- ;; CLOSE-FILE allows you to specify whether RESOURCE-FILENAME should be
- ;; closed or not after the search is over.
- ;; MAKE-CURRENT allows you to designate that RESOURCE-FILENAME be made the
- ;; current resource file (if CLOSE-FILE is non-nil).
- ;;
- (defun map-resources (type function &key resource-filename (close-file t) (make-current nil)
- &aux (file-refnum nil) (curresfile (_curresfile :errchk :word)))
- (unwind-protect
- (progn
- (if (probe-file resource-filename)
- (with-pstrs ((fn (expand-logical-namestring resource-filename)))
- (setq file-refnum (_openresfile :errchk :ptr fn :word))
- (_reserror :errchk)))
- (let ((count (count-types type))
- resource-handle)
- (if (/= count 0)
- (multiple-value-bind (high low)
- (restype-from-string type)
- (dotimes (i count)
- (setq resource-handle (_getindresource :word high :word low :word
- (1+ i) :ptr))
- (unless (and file-refnum
- (/= (_homeresfile :errchk :ptr resource-handle :word)
- file-refnum))
- (_hlock :errchk :A0 resource-handle :D0)
- (funcall function resource-handle)
- (_hlock :errchk :A0 resource-handle :D0)))))))
- (when (and close-file
- (numberp file-refnum))
- (_closeresfile :errchk :word file-refnum)
- (_reserror :errchk))
- (unless (and (not close-file)
- make-current)
- (_useresfile :errchk :word curresfile))))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;get-resource-handle
- ;;
- ;; Given the resource type and either its name or id, returns its handle.
- ;; If a resource-file is provided, then that one will be used.
- ;;
- (defun get-resource-handle (type name-or-id &optional resource-file &aux old-resource-file res)
- (setq old-resource-file (_curresfile :errchk :word))
- (unwind-protect
- (progn
- (unless (and (stringp type)
- (= (length type) 4))
- (error "TYPE SHOULD BE A STRING OF LENGTH 4."))
- (when (and resource-file
- (probe-file resource-file)
- (setq resource-file (expand-logical-namestring resource-file)))
- (with-pstrs ((fn resource-file))
- (setq resource-file (_openresfile :errchk :ptr fn :word)))
- (_useresfile :errchk :word resource-file))
- (multiple-value-bind (high low)
- (restype-from-string type)
- (cond ((stringp name-or-id)
- (with-pstrs ((name name-or-id))
- (setq res (_getnamedresource :word high :word low :ptr name :ptr))))
- ((numberp name-or-id)
- (setq res (_getresource :word high :word low :word name-or-id :ptr)))
- (t (error "A RESOURCE NAME OR ID SHOULD HAVE BEEN PROVIDED.")))))
- (_useresfile :errchk :word old-resource-file)
- res))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;get-resource-info
- ;;
- ;; Given a resource handle, it returns the resource type, id, name and size.
- ;; The type and name are Lisp strings; the id and size are numbers.
- ;;
- (defun get-resource-info (resource-handle)
- (or (handlep resource-handle)
- (error "~a SHOULD BE A RESOURCE HANDLE." resource-handle))
- (let ((res-size (_sizeresource :errchk :ptr resource-handle :long))
- res-id res-type res-name)
- (_hlock :errchk :A0 resource-handle)
- (unwind-protect
- (%stack-block ((id 4)
- (type 8)
- (name 256))
- (_getresinfo :errchk :ptr resource-handle :ptr id :ptr type :ptr name)
- (_reserror :errchk)
- (setq res-id (%get-word id)
- res-type (string-from-restype (ldb (byte 16 0) (%get-full-long type))
- (ldb (byte 16 16) (%get-full-long type)))
- res-name (%get-string name)))
- (_hunlock :errchk :A0 resource-handle))
- (values res-type res-id res-name res-size)))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;delete-resource
- ;;
- ;; Given a resource handle, it deletes the resource in the current resource file.
- ;;
- (defun delete-resource (resource-handle)
- (_rmveresource :errchk :ptr resource-handle)
- (_reserror :errchk)
- (_disposhandle :errchk :A0 resource-handle))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;get-unique-resource-id
- ;;
- ;; Given a resource type, it returns an unique resource id for it.
- ;; This id is guaranteed to be an id that
- ;; is not used by an already opened resource and not an id reserved
- ;; by the system.
- ;;
- (defun get-unique-resource-id (type &optional high low &aux id)
- (unless (and high low)
- (multiple-value-setq (high low)
- (restype-from-string type)))
- (setq id (_uniqueid :errchk :word high :word low :word))
- (_reserror :errchk)
- (if (< -1 id 128)
- (get-unique-resource-id type high low)
- id))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;transfer-resource
- ;;
- ;; Transfers a resource of given type and ID from resource file infile
- ;; into resource file outfile. If the optional keyword argument :infile is not provided, then
- ;; the current resource file is assumed to be the infile. If outfile
- ;; does not exist, then the outfile will be created. If optional keyword argument
- ;; :keep-outfile-open is non-nil, then outfile will be left in opened state
- ;; (default NIL). If optional keyword argument :delete-source is non-nil,
- ;; then the source resource is deleted after the transfer. If optional keyword
- ;; argument :destination-name is provided, it will be the name given to the
- ;; transfered resource in the outfile. If the optional keyword argument
- ;; :destination-id is provided, it will be the id given to the transfered
- ;; resource in the outfile. Note that you may use get-unique-resource-id
- ;; to obtain an unique resource id for a resource type.
- ;; You may safely use transfer-resource to change a resource's name and id
- ;; in a resource file by supplying the same argument for infile and outfile.
- ;; You will note that there is a variety of uses for transfer-resource.
- ;;
- (defun transfer-resource (type id outfile
- &key
- (infile nil)
- (keep-outfile-open nil)
- (delete-source nil)
- (destination-name nil)
- (destination-id nil))
- (let (resource-handle ; HANDLE TO RESOURCE TO BE COPIED
- a-resource-handle ; HANDLE TO A CONFLICTING RESOURCE WHICH MUST BE REMOVED BEFORE TRANSFER
- (from-map (not infile)) ; IF THERE'S NO INFILE, THEN USE RESOURCE MAP
- infile-refnum ; INFILE REFERENCE NUMBER
- created-outfile ; FLAG: DID WE CREATE THE OUTFILE? (FOR ERROR RECOVERY)
- outfile-refnum ; OUTFILE REFERENCE NUMBER
- type-high ; HIGH TWO CHARACTERS FOR RESOURCE TYPE CODE
- type-low ; LOW TWO CHARACTERS FOR RESOURCE TYPE CODE
- (old-resfile-refnum (_curresfile :errchk :word)) ; RESOURCE FILE REFERENCE NUMBER ACTIVE AT TIME OF CALL
- attributes ; FOR RESOURCE ATTRIBUTES
- res-type ; SOURCE RESOURCE TYPE
- res-id ; SOURCE RESOURCE ID
- res-name ; SOURCE RESOURCE NAME
- res-size ; SOURCE RESOURCE SIZE
- ; old-volume ; OLD VOLUME NUMBER
- ; (default-volume 0) ; DEFAULT VOLUME NUMBER
- error s ; FOR CATCH-ERROR-QUIETLY
- )
-
- (multiple-value-setq (s error)
- (catch-error-quietly
- ;; CHECK ARGUMENTS, OPEN AND CREATE FILES:
- (or (and (stringp type)
- (= (length type) 4))
- (error "RESOURCE TYPE (~S) MUST BE A STRING OF LENGTH 4." type))
- (multiple-value-setq (type-high type-low)
- (restype-from-string type))
- ;; OPEN/CREATE INFILE, IF NEEDED:
- (unless from-map
- (if (null (probe-file (pathname infile)))
- (error "INPUT FILE ~a NOT FOUND." infile)
- (setq infile (expand-logical-namestring infile)))
- (with-pstrs ((fn infile))
- (setq infile-refnum (_openresfile :errchk :ptr fn :word))))
- ;; OPEN OUTFILE:
- (or outfile
- (error "OUTFILE MISSING."))
- (setq outfile (expand-logical-namestring outfile))
- (with-pstrs ((fn outfile))
- (unless (probe-file outfile)
- (_createresfile :errchk :ptr fn)
- (_reserror :errchk)
- (setq created-outfile T))
- (setq outfile-refnum (_openresfile :errchk :ptr fn :word))
- (_reserror :errchk))
-
- ;; GET THE RESOURCE & CHECK ERRORS:
- (setq resource-handle
- (_getresource :word type-high :word type-low :word id :ptr))
- (_reserror :errchk)
- (print resource-handle)
- (if (or (null resource-handle)
- (and (not from-map)
- (/= (_homeresfile :errchk :ptr resource-handle :word)
- infile-refnum)))
- (error "Resource not found~@[ in file ~a~]." infile))
-
- (setq attributes (_getresattrs :errchk :ptr resource-handle :word))
- (multiple-value-setq (res-type res-id res-name res-size)
- (get-resource-info resource-handle))
- (_detachresource :errchk :ptr resource-handle)
- ;; IF ASKED, DELETE SOURCE RESOURCE:
- (when delete-source
- (setq a-resource-handle
- (get-resource-handle res-type res-id))
- (delete-resource a-resource-handle)
- (setq a-resource-handle nil))
- ;; SHOULD REALLY SET THE VOLUME REFERENCE NUMBER HERE...
- (_useresfile :errchk :word outfile-refnum)
- ;; NOW REMOVE ANY RESOURCES OF SAME TYPE & ID IN OUTPUT FILE:
- (loop
- (setq a-resource-handle
- (_getresource :word type-high :word type-low
- :word (or destination-id id) :ptr))
- (_reserror :errchk)
- (if (/= (_homeresfile :errchk :ptr a-resource-handle :word)
- outfile-refnum)
- (return nil)
- (delete-resource a-resource-handle)))
- (setq a-resource-handle nil) ; WATCH IT!
- ;; NOW WE CAN ADD THE RESOURCE!
- (with-pstrs ((name (or destination-name res-name)))
- (_addresource :errchk :ptr resource-handle
- :word type-high :word type-low
- :word (or destination-id id) :ptr name))
- (_reserror :errchk)
- (_SetResAttrs :errchk :ptr resource-handle :word attributes)
- (_reserror :errchk)
- (_changedresource :errchk :ptr resource-handle)
- (_reserror :errchk)
- (if keep-outfile-open
- (_writeresource :errchk :ptr resource-handle) ; WRITE RESOURCE TO FILE
- (_closeresfile :errchk :word outfile-refnum)) ; WRITES RESOURCE, TOO
- (_reserror :errchk)
- ))
-
- (_UseResFile :errchk :word old-resfile-refnum)
- (when error
- (and created-outfile
- (delete-file outfile))
- (error (car s) (cadr s)))))
-
-
- (provide ':resource-manager)
- (pushnew ':resource-manager *modules*)
-
-
-
- #| Examples:
-
- ;; OPEN A RESOURCE FILE:
- (open-resource-file "ccl;foo.rsrc")
-
- ;; HOW MANY cicn RESOURCES ARE THERE?
- (count-types "cicn")
-
- ;; PRINT INFORMATION ABOUT ALL cicn RESOURCES:
- (map-resources "cicn" #'(lambda (h)
- (multiple-value-bind (a b c d)
- (get-resource-info h)
- (print (list a b c d)))))
-
- ;; PRINT INFORMATION ABOUT ALL PICT RESOURCES IN FILE "ccl;foo.rsrc"
- (map-resources "PICT"
- #'(lambda (h)
- (multiple-value-bind (a b c d)
- (get-resource-info h)
- (print (list a b c d))))
- "ccl;foo.rsrc")
-
- ;; GET RESOURCE HANDLE FOR THE cicn RESOURCE NAMED "Star":
- (get-resource-handle "cicn" "Star")
-
- ;; GET INFORMATION ABOUT cicn RESOURCE NAMED "Star":
- (get-resource-info (get-resource-handle "cicn" "Star"))
-
- ;; Copy a cicn resource id 12341 to file "big disk:foobarbaz" and name it "Neat Icon",
- ;; deleting any resources in the outfile of the same type and id
- (transfer-resource "cicn" 12341 "big disk:foobarbaz" :destination-name "Neat Icon")
-
- ;; Check it out:
- (get-resource-info (get-resource-handle "cicn" "Neat Icon" "big disk:foobarbaz"))
-
- ;; Rename the last resource to "Really Neat Icon"
- (transfer-resource "cicn" 12341 "big disk:foobarbaz"
- :infile "big disk:foobarbaz"
- :destination-name "Really Neat Icon")
-
- ;; Check it out:
- (get-resource-info (get-resource-handle "cicn" "Really Neat Icon" "big disk:foobarbaz"))
-
- ;; Rename the last resource to "Excellent Icon" and change its id to 1991
- (transfer-resource "cicn" 12341 "big disk:foobarbaz"
- :infile "big disk:foobarbaz"
- :delete-source t
- :destination-id 1991
- :destination-name "Excellent Icon")
-
- ;; Check it out:
- (get-resource-info (get-resource-handle "cicn" "Excellent Icon" "big disk:foobarbaz"))
-
- |#